package client.comm.commlib.utils

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonSyntaxException
import com.google.gson.reflect.TypeToken
import java.io.InputStream
import java.io.InputStreamReader


val gson: Gson by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
    val builder = GsonBuilder()
//    builder.registerTypeAdapter(
//        JsonObject::class.java,
//        JsonDeserializer<Any> { jsonElement, type, jsonDeserializationContext -> jsonElement.asJsonObject })

    builder.registerTypeAdapter(Integer::class.java, IntegerJsonDeserializer())
    builder.registerTypeAdapter(String::class.java, StringJsonDeserializer())
    builder.registerTypeAdapter(Double::class.java, DoubleJsonDeserializer())
    builder.registerTypeAdapter(Float::class.java, FloatJsonDeserializer())
    builder.disableHtmlEscaping().create()
}

inline fun <reified T> String?.fromJson(): T? {
    if (isNullOrEmpty()) {
        return null
    }
    return try {
        val clazz = T::class.java
        gson.fromJson(this, clazz)
    } catch (e: JsonSyntaxException) {
        e.printStackTrace()
        null
    }
}

inline fun <reified T> String?.listFromJson(): T? {
    if (isNullOrEmpty()) {
        return null
    }
    return try {
        val clazz = T::class.java
//        gson.fromJson(this, TypeToken<ArrayList<T>>().type)
        gson.fromJson(this, object : TypeToken<T>() {
        }.type)

    } catch (e: JsonSyntaxException) {
        e.printStackTrace()
        null
    }
}
inline fun <reified T> InputStream?.listFromPath(): T? {
    return try {
        gson.fromJson(InputStreamReader(this),T::class.java)
    } catch (e: JsonSyntaxException) {
        e.printStackTrace()
        null
    }
}
fun Any.isNotNull(): Boolean {
    val str = this.toString() + ""
    return ("" != str && "null" != str)
}
fun Any.toJson(): String? {
    return if (isNotNull()) {
        null
    } else gson.toJson(this)
}

inline fun <reified T> Any.fromObject(): T {
    val clazz = T::class.java
    val element = gson.toJsonTree(this)
    return gson.fromJson(element, clazz)
}

inline fun <reified T> String?.fromJson(token: TypeToken<T>): T? {
    if (this.isNullOrEmpty()) {
        return null
    }
    return try {
        gson.fromJson<T>(this, token.type)
    } catch (e: JsonSyntaxException) {
        null
    }
}

fun Any.toMap(): Map<String, Any> {
    val element = gson.toJsonTree(this)
    return gson.fromJson<Map<String, Any>>(element, Map::class.java)
}

